/*
 * RtpCaster.cpp
 *
 *  Created on: 2016年4月23日
 *      Author: terry
 */

#include "BasicType.h"
#include "RtpCaster.h"
#include "Application.h"
#include "CCasterChannel.h"
#include "CLog.h"
#include "RtpPort.h"
#include "MediaType.h"
#include <errno.h>
#include "CRtpSink.h"
#include "CTcpSink.h"


av::CasterChannelTable& getChannelTable()
{
	return Application::instance().getChannelTable();
}

static av::CasterChannelPtr getChannel(HANDLE handle)
{
	av::CasterChannelPtr chl;
	getChannelTable().find(handle, chl);
	return chl;
}



DLLEXPORT int rtpcaster_init()
{
    CLog::setLogger(CLog::COUT);
    CLog::info("rtpcaster_init\n");

	int rc = Application::instance().init();
	if (rc != 0)
	{
		return rc;
	}

	return rc;
}

DLLEXPORT int rtpcaster_quit()
{
	Application::instance().quit();

	return 0;
}

DLLEXPORT int rtpcaster_set_port_range(int minPort, int maxPort)
{
    if ((minPort < 0) || (maxPort < 0))
    {
        return EINVAL;
    }

    av::RtpPort::setRange(minPort, maxPort);

	return 0;
}

DLLEXPORT int rtpcaster_create_channel(HANDLE* handle, int codec, int clockRate, int outPort, int ssrc)
{
	if (codec < 0 || clockRate <= 0)
	{
		return EINVAL;
	}

	av::CasterChannelTable& chlTable = getChannelTable();

	av::CasterChannelPtr chl(new av::CCasterChannel());
	int rc = chl->open(codec, clockRate, outPort, ssrc);
	if (rc != 0)
	{
		return rc;
	}

	chlTable.put(chl.get(), chl);

    *handle = chl.get();

	return 0;
}

DLLEXPORT void rtpcaster_destroy_channel(HANDLE handle)
{
	av::CasterChannelTable& chlTable = getChannelTable();
    av::CasterChannelPtr chl = getChannel(handle);
    if (!chl)
    {
        return;
    }

	chlTable.remove(handle);

	return ;
}

DLLEXPORT int rtpcaster_add_target(HANDLE handle, int protocol, const char* ip, int port)
{
	av::CasterChannelPtr chl = getChannel(handle);
	if (!chl)
	{
		return ENOENT;
	}

	return chl->addTarget(protocol, ip, port);
}

DLLEXPORT int rtpcaster_remove_target(HANDLE handle, int protocol, const char* ip, int port)
{
	av::CasterChannelPtr chl = getChannel(handle);
	if (!chl)
	{
		return ENOENT;
	}

	return chl->removeTarget(protocol, ip, port);
}

DLLEXPORT int rtpcaster_remove_all_target(HANDLE handle, int protocol)
{
	av::CasterChannelPtr chl = getChannel(handle);
	if (!chl)
	{
		return ENOENT;
	}

	return chl->removeAllTarget(protocol);
}

DLLEXPORT int rtpcaster_write_data(HANDLE handle, uint8_t* data, int size, int64_t pts, int flags)
{
	av::CasterChannelPtr chl = getChannel(handle);
	if (!chl)
	{
		return ENOENT;
	}

	av::MediaPacketPtr mpkt(new av::MediaPacket());
	mpkt->type = av::MEDIA_TYPE_DATA;
	mpkt->set(data, size);
	mpkt->pts = pts;
	mpkt->flags = flags;

	return chl->write(mpkt);
}



static av::RtpSinkTable& getSinkTable()
{
	return Application::instance().getSinkTable();
}

static av::RtpSinkPtr getSink(HANDLE handle)
{
	av::RtpSinkPtr sink;
	getSinkTable().find(handle, sink);
	return sink;
}

/**
 * 打开RTP接收端
 * @param handle	RTP句柄
 * @param protocol	协议 @see RtpProtocol
 * @param port		端口
 * @return 0 表示成功
 */
DLLEXPORT int rtpsink_open(HANDLE* handle, int protocol, int port)
{
	av::RtpSinkPtr sink;
	if (protocol == kProtocolUdp)
	{
		sink.reset(new av::CRtpSink());
	}
	else if (protocol == kProtocolTcp)
	{
		sink.reset(new av::CTcpSink());
	}
	else
	{
		return ENOSYS;
	}

	int rc = sink->open(port);
	if (rc != 0)
	{
		return rc;
	}

	av::RtpSinkTable& sinkTable = getSinkTable();
	sinkTable.put(sink.get(), sink);

	*handle = sink.get();

	return 0;

}

/**
 * 设置接收回调
 * @param handle
 * @param cb		回调函数
 * @param context	回调环境
 */
DLLEXPORT void rtpsink_set_callback(HANDLE handle, RtpSinkCallback cb, void* context)
{
	av::RtpSinkPtr sink = getSink(handle);
	if (!sink)
	{
		return ;
	}

	sink->setCallback(cb, context);
}

/**
 * 设置媒体格式
 * @param handle
 * @param codec		编码格式
 * @param clockRate	时钟频率, 视频为90000, 音频为采样率
 * @return
 */
DLLEXPORT int rtpsink_set_format(HANDLE handle, int codec, int clockRate)
{
	av::RtpSinkPtr sink = getSink(handle);
	if (!sink)
	{
		return ENOENT;
	}

	sink->setFormat(codec, clockRate);
	return 0;
}

/**
 * 关闭RTP
 * @param handle
 */
DLLEXPORT void rtpsink_close(HANDLE handle)
{
	av::RtpSinkPtr sink = getSink(handle);
	if (!sink)
	{
		return;
	}

	sink->close();

	av::RtpSinkTable& sinkTable = getSinkTable();
	sinkTable.remove(handle);
}

/**
 * 设置缓存队列长度, 单位为RTP包个数.
 * 该队列用户处理RTP包乱序
 * @param handle
 * @param size
 */
DLLEXPORT void rtpsink_set_cache(HANDLE handle, int size)
{
	av::RtpSinkPtr sink = getSink(handle);
	if (!sink)
	{
		return ;
	}

	sink->setCacheSize(size);

	return ;
}

DLLEXPORT int rtpsink_get_port(HANDLE handle)
{
	av::RtpSinkPtr sink = getSink(handle);
	if (!sink)
	{
		return 0;
	}

	return sink->getPort();
}

/*
DLLEXPORT int rtpsink_set_format_url(HANDLE handle, const char* url)
{
	av::RtpSinkPtr sink = getSink(handle);
	if (!sink)
	{
		return 0;
	}

	return sink->setFormat();
}

*/
